package com.sunny.search.api.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.sunny.search.api.service.BaseService;
import com.sunny.search.api.service.SellerGoodsService;
import com.sunny.search.model.entity.SellerGoodsInfo;
import com.sunny.search.model.pojo.common.HighlightInfo;
import com.sunny.search.model.pojo.common.SortInfo;
import com.sunny.search.model.pojo.query.SellerGoodsQuery;
import com.sunny.search.model.pojo.vo.PageAggsVO;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.MatchQueryBuilder;
import org.elasticsearch.index.query.Operator;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.aggregations.AggregationBuilder;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.SortBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;

/**
 * @author fengxiangyang
 * @date 2018/12/24
 */
@Service
public class SellerGoodsServiceImpl extends BaseService implements SellerGoodsService {
    private static final Logger LOGGER = LoggerFactory.getLogger(SellerGoodsServiceImpl.class);

    @Override
    public PageAggsVO<SellerGoodsInfo> search(SellerGoodsQuery query) {
        final List<String> list = correlationRecell(query);

        return null;
    }

    /**
     * 相关度召回
     * @param query
     * @return
     */
    private List<String> correlationRecell(SellerGoodsQuery query){
        final String key = query.getKey();
        final List<Integer> brandIds = query.getBrandIds();
        final String categoryNo = query.getCategoryNo();
        final List<Long> attrValueIds = query.getAttrValueIds();
        SearchRequest searchRequest = new SearchRequest(INDEX_NAME).types("_doc");
        //构建查询对象
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        //截断
        searchSourceBuilder.size(RECALL_SIZE);
        //返回字段
        searchSourceBuilder.fetchSource(query.getFields(), new String[]{"_type"});
        //布尔查询
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        if(StringUtils.isNotBlank(key)){
            if(query.isRewriteFlag()){
                //TODO: QR查询语句
            }else{
                List<QueryBuilder> shouldBuilder = new ArrayList<>();
                Matcher matcher = NUMBER_PATTERN.matcher(key);
                if (matcher.matches()) {
                    shouldBuilder.add(QueryBuilders.termQuery("_id", key).boost(8));
                }
                shouldBuilder.add(QueryBuilders.matchPhraseQuery("buyNo", key).boost(4));
                shouldBuilder.add(QueryBuilders.matchPhraseQuery("model", key).boost(4));
                shouldBuilder.add(QueryBuilders.matchQuery("title", key).operator(Operator.AND).boost(2));
                shouldBuilder.add(QueryBuilders.matchQuery("categoryNames", key).operator(Operator.AND).boost(1));
                shouldBuilder.add(QueryBuilders.matchQuery("brandNames", key).operator(Operator.AND).boost(1));
                boolQueryBuilder.minimumShouldMatch(1).should().addAll(shouldBuilder);
            }
        }
        if (StringUtils.isNotBlank(categoryNo)) {
            boolQueryBuilder.filter().add(QueryBuilders.termQuery("categoryNo",categoryNo));
        }
        if (CollectionUtils.isNotEmpty(brandIds)) {
            boolQueryBuilder.filter().add(QueryBuilders.termsQuery("brandId",brandIds));
        }
        if (CollectionUtils.isNotEmpty(attrValueIds)) {
            boolQueryBuilder.filter().add(QueryBuilders.termsQuery("attrValueId",attrValueIds));
        }
        searchRequest.source(searchSourceBuilder);
        SearchResponse searchResponse = elasticsearchHandler.search(searchRequest);
        SearchHit[] searchHits = searchResponse.getHits().getHits();
        List<String> list = new ArrayList<>();
        for (SearchHit searchHit : searchHits) {
            list.add(searchHit.getId());
        }
        if(CollectionUtils.isEmpty(list)){
            //TODO: 兜底服务
        }
        return list;
    }

    /**
     * 重排序
     * @param list
     */
    private List<SellerGoodsInfo> rerank(List<SellerGoodsInfo> list) {
        List<SellerGoodsInfo> rerankList = new ArrayList<>();
        while (CollectionUtils.isNotEmpty(list)) {
            final Map<Integer, SellerGoodsInfo> linkedHashMap = getLinkedHashMap(list);
            rerankList.addAll(linkedHashMap.values());
        }
        return rerankList;
    }

    /**
     * 筛选不同品牌
     * @param list
     * @return
     */
    private Map<Integer,SellerGoodsInfo> getLinkedHashMap(List<SellerGoodsInfo> list){
        Map<Integer,SellerGoodsInfo> data = new LinkedHashMap<>();
        final Iterator<SellerGoodsInfo> iterator = list.iterator();
        while (iterator.hasNext()){
            final SellerGoodsInfo next = iterator.next();
            final Integer brandId = next.getBrandId();
            if(data.get(brandId) == null){
                data.put(brandId,next);
                iterator.remove();
            }
        }
        return data;
    }

    private List<SellerGoodsInfo> subList(List<SellerGoodsInfo> list, Integer page, Integer size){
        Integer start = (page - 1) * size;
        Integer end = page * size;
        List<SellerGoodsInfo> resultList;
        if(list.size() >= end ){
            resultList = list.subList(start, end);
        }else{
            resultList = list.subList(start,list.size()-1);
        }
        return resultList;
    }


    /**
     * 结果集详情
     * @param query
     * @return
     */
    private PageAggsVO<SellerGoodsInfo> getResult(SellerGoodsQuery query, List<String> resultList){
        final String key = query.getKey();
        SearchRequest searchRequest = new SearchRequest(INDEX_NAME).types("_doc");
        /**
         * 构建查询对象
         */
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.size(query.getPageSize());
        searchSourceBuilder.fetchSource(query.getFields(), new String[]{"_type"});
        //排序
        final List<SortInfo> sortInfoList = query.getSortInfoList();
        final List<SortBuilder<?>> sortBuilder = baseSortBuilder(sortInfoList);
        if(sortBuilder != null){
            sortBuilder.forEach( o -> searchSourceBuilder.sort(o));
        }
        //高亮
        final HighlightBuilder highlightBuilder = baseHighlightBuilder(query.getHighlightInfo());
        if(highlightBuilder != null){
            searchSourceBuilder.highlighter(highlightBuilder);
        }
        //聚合
        final List<AggregationBuilder> aggregationBuilders = baseAggregationBuilders(query.getAggregationInfoList());
        if(aggregationBuilders != null){
            aggregationBuilders.forEach(o -> searchSourceBuilder.aggregation(o));
        }
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        if(StringUtils.isNotBlank(key)){
            final MatchQueryBuilder titleQueryBuilder = QueryBuilders.matchQuery("title", key).operator(Operator.AND);
            boolQueryBuilder.minimumShouldMatch(0).should(titleQueryBuilder);
        }
        boolQueryBuilder.filter().add(QueryBuilders.termsQuery("_id",resultList));
        searchRequest.source(searchSourceBuilder);
        SearchResponse searchResponse = elasticsearchHandler.search(searchRequest);
        SearchHit[] searchHits = searchResponse.getHits().getHits();
        final HighlightInfo highlightInfo = query.getHighlightInfo();
        List<SellerGoodsInfo> list = new ArrayList<>();
        for (SearchHit searchHit : searchHits) {
            JSONObject hitJSONObject = getHitJSONObject(searchHit, highlightInfo);
            SellerGoodsInfo sellerGoodsInfo = JSONObject.toJavaObject(hitJSONObject, SellerGoodsInfo.class);
            list.add(sellerGoodsInfo);
        }
        //重排序
        if (CollectionUtils.isEmpty(sortInfoList)) {
            list = rerank(list);
        }
        //截取结果
        subList(list,query.getPageNo(),query.getPageSize());
        final PageAggsVO<SellerGoodsInfo> pageAggsVO = new PageAggsVO<>(query.getPageNo(), query.getPageSize(), list);
        //聚合结果信息
        final Aggregations aggregations = searchResponse.getAggregations();
        final Map<String, Collection<?>> aggregationVO = getAggregationVO(aggregations,query.getAggregationInfoList());
        pageAggsVO.setAggregations(aggregationVO);
        return pageAggsVO;
    }

}
